package gallery.gif;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;


/**
 * GifView<br>
 * 本类可以显示一个gif动画，其使用方法和android的其它view（如imageview)一样。<br>
 * 如果要显示的gif太大，会出现OOM的问题。
 *
 * @author liao
 */
public class GifView extends View implements GifAction {

    private static List<Bitmap> list = new ArrayList<Bitmap>();
    private GifImageType animationType = GifImageType.SYNC_DECODER;
    private HashSet<GifFrame> bitmapSet = new HashSet<GifFrame>();
    /**
     * 当前要画的帧的图
     */
    private Bitmap currentImage = null;
    private DrawThread drawThread = null;
    /**
     * gif解码器
     */
    private GifDecoder gifDecoder = null;
    private int imageid;
    /**
     * 用于判断尺寸是否确定下来
     */
    private boolean isHeightSetted;
    private boolean isRun = true;
    private boolean pause = false;
    private Rect rect = new Rect();
    private Handler redrawHandler = new Handler() {
        public void handleMessage(Message msg) {
            invalidate();
        }
    };

    public GifView(Context context) {
        super(context);

    }

    public GifView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GifView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }

    public static List<Bitmap> getBitmap() {
        return list;
    }

    public boolean isStop() {
        return pause;
    }

    public void parseOk(boolean parseStatus, int frameIndex) {
        if (parseStatus) {
            if (gifDecoder != null) {
                switch (animationType) {
                    case WAIT_FINISH:
                        if (frameIndex == -1) {
                            if (gifDecoder.getFrameCount() > 1) {     //当帧数大于1时，启动动画线程
                                DrawThread dt = new DrawThread();
                                dt.start();
                            } else {
                                reDraw();
                            }
                        }
                        break;
                    case COVER:
                        if (frameIndex == 1) {
                            currentImage = gifDecoder.getImage();
                            reDraw();
                        } else if (frameIndex == -1) {
                            if (gifDecoder.getFrameCount() > 1) {
                                if (drawThread == null) {
                                    drawThread = new DrawThread();
                                    drawThread.start();
                                }
                            } else {
                                reDraw();
                            }
                        }
                        break;
                    case SYNC_DECODER:
                        if (frameIndex == 1) {
                            currentImage = gifDecoder.getImage();
                            reDraw();
                        } else if (frameIndex == -1) {
                            reDraw();
                        } else {
                            if (drawThread == null) {
                                drawThread = new DrawThread();
                                drawThread.start();
                            }
                        }
                        break;
                }

            } else {
                Log.e("gif", "parse error");
            }

        }
    }

    private void reDraw() {
        if (redrawHandler != null) {
            Message msg = redrawHandler.obtainMessage();
            redrawHandler.sendMessage(msg);
        }
    }

    /**
     * 以资源形式设置gif图片
     *
     * @param resId gif图片的资源ID
     */
    public void setGifImage(int resId) {
        if (resId != imageid) {
            imageid = resId;
        } else {
            return;
        }
        Resources r = this.getResources();
        InputStream is = r.openRawResource(resId);
        setGifDecoderImage(is);
    }

    /**
     * 以字节数据形式设置gif图片
     *
     * @param gif 图片
     */
    public void setGifImage(byte[] gif) {
        setGifDecoderImage(gif);
    }

    /**
     * 设置图片，并开始解码
     *
     * @param gif 要设置的图片
     */
    private void setGifDecoderImage(byte[] gif) {
        if (gifDecoder != null) {
            gifDecoder.free();
            gifDecoder = null;
        }
        gifDecoder = new GifDecoder(gif, this);
        gifDecoder.start();
        requestLayout();
    }

    /**
     * 以字节流形式设置gif图片
     *
     * @param is 图片
     */
    public void setGifImage(InputStream is) {
        setGifDecoderImage(is);
    }

    /**
     * 设置图片，开始解码
     *
     * @param is 要设置的图片
     */
    private void setGifDecoderImage(InputStream is) {
        if (gifDecoder != null) {
            gifDecoder.free();
            gifDecoder = null;
        }
        gifDecoder = new GifDecoder(is, this);
        gifDecoder.start();
        requestLayout();
    }

    /**
     * 设置gif在解码过程中的显示方式<br>
     * <strong>本方法只能在setGifImage方法之前设置，否则设置无效</strong>
     *
     * @param type 显示方式
     */
    public void setGifImageType(GifImageType type) {
        if (gifDecoder == null) {
            animationType = type;
        }
    }

    /**
     * 继续显示动画<br>
     * 本方法在调用showCover后，会让动画继续显示，如果没有调用showCover方法，则没有任何效果
     */
    public void showAnimation() {
        System.out.println("showAnimation_____________________________________");
        pause = false;
    }

    /**
     * 只显示第一帧图片<br>
     * 调用本方法后，gif不会显示动画，只会显示gif的第一帧图
     */
    public void showCover() {
        System.out.println("showCover_____________________________________");
        pause = true;
        if (gifDecoder == null) {
            return;
        }

        //    	currentImage = gifDecoder.getImage();
        invalidate();
    }

    /**
     * 解码过程中，Gif动画显示的方式<br>
     * 如果图片较大，那么解码过程会比较长，这个解码过程中，gif如何显示
     *
     * @author liao
     */
    public enum GifImageType {
        /**
         * 在解码过程中，不显示图片，直到解码全部成功后，再显示
         */
        WAIT_FINISH(0),
        /**
         * 和解码过程同步，解码进行到哪里，图片显示到哪里
         */
        SYNC_DECODER(1),
        /**
         * 在解码过程中，只显示第一帧图片
         */
        COVER(2);

        final int nativeInt;

        GifImageType(int i) {
            nativeInt = i;
        }
    }

    /**
     * 动画线程
     *
     * @author liao
     */
    private class DrawThread extends Thread {
        public void run() {
            if (gifDecoder == null) {
                return;
            }
            while (isRun) {
                if (!pause) {
                    //if(gifDecoder.parseOk()){
                    try {
                        GifFrame frame = gifDecoder.next();
                        bitmapSet.add(frame);
                        currentImage = frame.image;
                        long sp = frame.delay;
                        if (redrawHandler != null) {
                            Message msg = redrawHandler.obtainMessage();
                            redrawHandler.sendMessage(msg);
                            SystemClock.sleep(sp);
                        } else {
                            break;
                        }

                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                    //	    			}else{
                    //	    				currentImage = gifDecoder.getImage();
                    //	    				break;
                    //	    			}
                } else {
                    SystemClock.sleep(100);
                }
            }
            recycle();
            System.out.println("recycle() gif");
        }
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (gifDecoder == null) {
            return;
        }
        if (currentImage == null) {
            currentImage = gifDecoder.getImage();
        }
        if (currentImage == null) {
            return;
        }
        int saveCount = canvas.getSaveCount();
        canvas.save();
        canvas.translate(getPaddingLeft(), getPaddingTop());
        canvas.drawBitmap(currentImage, null, rect, null);
        if (!isHeightSetted) {
            requestLayout();
        }
        if (!list.contains(currentImage)) {
            list.add(currentImage);
        }
        canvas.restoreToCount(saveCount);
    }

    ;

    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        isRun = false;
        if (null != drawThread) {
            drawThread.interrupt();
        }
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        switch (MeasureSpec.getMode(widthMeasureSpec)) {
            case MeasureSpec.EXACTLY:
                break;
            case MeasureSpec.AT_MOST:
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
        }

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (gifDecoder != null) {
            isHeightSetted = gifDecoder.height != 0;
            if (isHeightSetted) {
                heightSize = gifDecoder.height * widthSize / gifDecoder.width;
            }
        }
        rect.left = 0;
        rect.top = 0;
        rect.right = widthSize;
        rect.bottom = heightSize;
        setMeasuredDimension(widthSize, heightSize);
    }

    private void recycle() {
        for (GifFrame frame : bitmapSet) {
            if (null != frame.image && !frame.image.isRecycled()) {
                frame.image.recycle();
            }
        }
    }
}
